#pragma once
#include "hashtable.h"





namespace HashBucket
{

    template<class K, class V, class Hash = MyHashFunc::MyHash<K>>
    class unordered_map
    {
        struct KeyOfValue
        {
            const K& operator()(const pair<K, V> &_kv)
            {
                return _kv.first;
            }
        };

    public: 
        typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfValue, Hash> HT;
        typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfValue, Hash>::Iterator Iterator;
        typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfValue, Hash>::const_Iterator const_Iterator;

        Iterator begin()
        {
            return _ht.begin();            
        }

        const_Iterator begin() const 
        {
            return _ht.begin();
        }

        Iterator end()
        {
            return _ht.end();
        }
        
        const_Iterator end() const 
        {
            return _ht.end();
        }

        V &operator[](const K &key)
        {
            pair<Iterator, bool> ret = _ht.Insert(make_pair(key, V()));
            return (ret.first)->second;
        }

        pair<Iterator, bool> Insert(const pair<K, V> &data)
        {
            return _ht.Insert(data);
        }



        void Order()
        {
            _ht.Order();
        }


    private:
        HT _ht;


    public:
        static void Test1()
        {
            HashBucket::unordered_map<int, int> mp;
            mp.Insert({1, 1});
            mp.Insert({12, 1});
            mp.Insert({13, 1});
            mp.Insert({14, 1});
            mp.Insert({15, 1});
            mp.Insert({16, 1});
            mp.Insert({17, 1});
            mp.Insert({18, 1});

            mp.Order();
        }

        static void Test2()
        {
            HashBucket::unordered_map<int, int> mp;
            mp.Insert({1, 1});
            mp.Insert({12, 1});
            mp.Insert({13, 1});
            mp.Insert({14, 1});
            mp.Insert({15, 1});
            mp.Insert({16, 1});
            mp.Insert({17, 1});
            mp.Insert({18, 1});

            unordered_map<int, int>::Iterator it = mp.begin();
            for (auto &[x, y] : mp)
            {
                cout << x << ":" << y << endl;
            }
        }

        static void Test3()
        {
            HashBucket::unordered_map<int, int> mp;
            mp.Insert({1, 1});
            mp.Insert({12, 1});
            mp.Insert({13, 1});
            mp.Insert({14, 1});
            mp.Insert({15, 1});
            mp.Insert({16, 1});
            mp.Insert({17, 1});
            mp.Insert({18, 1});

            unordered_map<int, int>::Iterator it = mp.begin();

            while (it != mp.end())
            {
                cout << (*it).first << " ";
                ++it;
            }
            it = mp.begin();
            while (it != mp.end())
            {
                cout << (*it).first << " ";
                ++it;
            }

        }

        static void Test4()
        {
            HashBucket::unordered_map<int, int> mp;

            mp[1] = 1;
            mp[12] = 1;
            mp[13] = 1;
            mp[14] = 1;
            mp[15] = 1;
            mp[16] = 1;
            mp[17] = 1;
            mp[18] = 1;

            unordered_map<int, int>::Iterator it = mp.begin();

            while (it != mp.end())
            {
                cout << (*it).first << " ";
                ++it;
            }
        }

    };


};